#include "encoderwindow.h"
#include "ui_encoderwindow.h"

#include <QTextCodec>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
#include <QFileDialog>
#include <QDirIterator>
#include <QRegExp>
#include <QTextStream>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QUrl>
#include <QAction>

EncoderWindow::EncoderWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::EncoderWindow)
{
    ui->setupUi(this);

    lastDir = QDir::homePath();
    initCodec();
    // init ui
    createMenu();
    foreach(QTextCodec *codec ,codecList){
        ui->destEncodeComboBox->addItem(codec->name(),
                                        codec->mibEnum());
        // dest default UTF-8
        ui->destEncodeComboBox->setCurrentIndex(1);
        ui->srcEncodeComboBox->addItem(codec->name(),
                                       codec->mibEnum());
    }
    // connection
    connect(exitAct,SIGNAL(triggered()),this,SLOT(close()));
    connect(aboutQtAct,SIGNAL(triggered()),qApp,SLOT(aboutQt()));
    connect(aboutAct,SIGNAL(triggered()),this,SLOT(about()));

    connect(ui->srcDirPushButton,SIGNAL(clicked()),this,SLOT(selectSrcDir()));
    connect(ui->destDirPushButton,SIGNAL(clicked()),this,SLOT(selectDestDir()));
    connect(ui->convertPushButton,SIGNAL(clicked()),this,SLOT(encodeDir()));
    connect(ui->exitPushButton,SIGNAL(clicked()),this,SLOT(close()));

    connect(this,SIGNAL(EncodeStarted()),this,SLOT(start()));
    connect(this,SIGNAL(EncodeCompleted(int)),this,SLOT(complete(int)));

    setAcceptDrops(true);
}

EncoderWindow::~EncoderWindow()
{
    delete ui;
}

void EncoderWindow::initCodec(){
    QRegExp iso8859RegExp("ISO[- ]8859-([0-9]+).*");
    QMap<QString,QTextCodec *> codecMap;
    QTextCodec *localeCodec = QTextCodec::codecForLocale();
    foreach(int mib , QTextCodec::availableMibs()){
        QTextCodec *codec = QTextCodec::codecForMib(mib);
        QString sortKey = codec->name().toUpper();
        int rank;
        if(codec->mibEnum()==localeCodec->mibEnum()){
            rank=0;
        }else if(sortKey.startsWith("UTF-8")){
            rank=1;
        }else if(sortKey.startsWith("UTF-16")){
            rank=2;
        }else if(iso8859RegExp.exactMatch(sortKey)){
            if(iso8859RegExp.cap(1).size()==1)
                rank = 3;
            else
                rank = 4;
        }else{
            rank=5;
        }
        sortKey.prepend(QChar('0'+rank));
        codecMap.insert(sortKey,codec);
    }
    codecList = codecMap.values();
}

QString EncoderWindow::selectDir(){
    QString dirStr = QFileDialog::getExistingDirectory(
                this,tr("Select Dir"),lastDir);
    if(!dirStr.isEmpty()){
        QDir dir(dirStr);
        if(dir.exists()){
            if(dir.cdUp()){
                lastDir = dir.path();
            }
        }
    }
    return dirStr;
}

void EncoderWindow::selectSrcDir(){
    ui->srcDirLineEdit->setText(selectDir());
}

void EncoderWindow::selectDestDir(){
    ui->destDirLineEdit->setText(selectDir());
}

int EncoderWindow::encodeFile(const QFileInfo &info
                           ,const QFileInfo &newInfo)
{
    QFile file(info.filePath());
    if(!file.open(QIODevice::ReadOnly)){   
        return FAILURE;
    }

    QByteArray data = file.readAll();
    file.close();

    QTextCodec *srcDecodec = codecList.at(
                ui->srcEncodeComboBox->currentIndex());
    QTextCodec *destDecodec = codecList.at(
                ui->destEncodeComboBox->currentIndex());

    QString str = srcDecodec->toUnicode(data);
    QFile newFile(newInfo.filePath());
    if(!newFile.open(QIODevice::WriteOnly)){
        return FAILURE;
    }

    QTextStream out(&newFile);
    out.setCodec(destDecodec);
    out<<str;
    newFile.close();

    return SUCCESS;
}

void EncoderWindow::createMenu(){
    // action
    exitAct = new QAction(tr("E&xit"), this);

    aboutAct = new QAction(tr("&About"), this);
    aboutQtAct = new QAction(tr("About &Qt"), this);
    // menu
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(exitAct);

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
}

void EncoderWindow::encodeDir(){

    emit EncodeStarted();

    int srcMib = ui->srcEncodeComboBox->itemData(
                ui->srcEncodeComboBox->currentIndex()).toInt();
    int destMib = ui->destEncodeComboBox->itemData(
                ui->destEncodeComboBox->currentIndex()).toInt();

    if(srcMib == destMib){
        QMessageBox::information(this,tr("Info"),tr("encodings are same."));
        emit EncodeCompleted(FAILURE);
        return;
    }

    QDir dir(ui->srcDirLineEdit->text());
    if(!dir.exists()){
        QMessageBox::information(this,tr("Info"),tr("dir doesn't exist."));
        emit EncodeCompleted(FAILURE);
        return;
    }

    QDir destDir(ui->destDirLineEdit->text());
    if(!destDir.exists()){
        QMessageBox::information(this,tr("Info"),tr("destination dir doesn't exist."));
        emit EncodeCompleted(FAILURE);
        return;
    }

    if(dir==destDir){
        int ret = QMessageBox::question(this,tr("Warning"),
                              tr("srouce dir equal to destination dir, continue?"),
                              QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
        if(ret == QMessageBox::No){
            emit EncodeCompleted(FAILURE);
            return;
        }
    }

    QDirIterator iter(dir, QDirIterator::Subdirectories);
    QString strRegex = ui->filterLineEdit->text();
    QRegExp fileRegex(strRegex);
    while (iter.hasNext()) {
        iter.next();
        QFileInfo info = iter.fileInfo();
        if(!info.isFile()){
            continue;
        }
        if (strRegex.size()!=0 &&
                !fileRegex.exactMatch(info.fileName())) {
            continue;
        }

        // create new file path and its' path.
        QString relativePath = info.canonicalFilePath().mid(
                    ui->srcDirLineEdit->text().size());


        QString newFilePath(ui->destDirLineEdit->text());
        newFilePath.append(relativePath);

        QFileInfo relNewFileInfo(newFilePath);
        if(!relNewFileInfo.dir().exists()){
            if(!relNewFileInfo.dir().mkpath(".")){
                QMessageBox::warning(this,tr("Warning"),
                                     tr("create dir error, \"%1\"").arg(relNewFileInfo.dir().path()));
                emit EncodeCompleted(FAILURE);
                return;
            }
        }
        //
        if(encodeFile(info,relNewFileInfo)!=SUCCESS){
            QMessageBox::warning(this,tr("Warning"),
                                 tr("encode fail error, \"%1\"").arg(newFilePath));
            emit EncodeCompleted(FAILURE);
            return;
        }
    }

    emit EncodeCompleted(SUCCESS);
}

void EncoderWindow::highightSrcDir(bool on){
    if(on){
        ui->srcDirLineEdit->setStyleSheet("QLineEdit{background:#FFFFAA;}");
    }else{
        ui->srcDirLineEdit->setStyleSheet("QLineEdit{background:white;}");
    }
}

void EncoderWindow::dragEnterEvent(QDragEnterEvent *event){
    const QMimeData *mime = event->mimeData();
    if(!mime->hasUrls()){
        return;
    }

    foreach(QUrl url,mime->urls()){
        if(url.isLocalFile()){
            highightSrcDir(true);
            event->acceptProposedAction();
            return;
        }
    }
}

void EncoderWindow::dragLeaveEvent(QDragLeaveEvent *event){
    highightSrcDir(false);
    event->accept();
}

void EncoderWindow::dropEvent(QDropEvent *event){
    // set dir
    const QMimeData *mime = event->mimeData();
    if(mime->hasUrls()){
        foreach(QUrl url,mime->urls()){
            if(!url.isLocalFile()){
                continue;
            }
            QFileInfo file(url.toLocalFile());
            if(!file.isDir()){
                continue;
            }
            ui->srcDirLineEdit->setText(url.toLocalFile());
            break;
        }
    }
    highightSrcDir(false);
    event->acceptProposedAction();
}

void EncoderWindow::start(){
    ui->convertPushButton->setEnabled(false);
}

void EncoderWindow::complete(int rst){
    if(rst==SUCCESS){
        QMessageBox::information(this,tr("Info"),tr("complete"));
    }
    ui->convertPushButton->setEnabled(true);
}

void EncoderWindow::about(){
    QMessageBox::about(this, tr("About Application"),
             tr("Author:Guo Jingwei, Mail:gjwgogo@163.com;gjwgogo@gmail.com"));
}
